Skip to main content
  1. posts/

The Race That Debugged My Software

More than 15 years ago, I worked for a company that produced gym training machines. One of those machines was a kayak ergometer—essentially an indoor kayaking simulator. My job was to write firmware for a device that connected to the ergometer and translated sensor data into something athletes could understand and see: speed, force, distance, and so on.

One day, the company owner came to me with a new idea.

Now that we have all this data being sent to the computer, can you build a piece of software that simulates an actual kayak race?

Challenge accepted.

Turning Data Into a Real Race #

I went straight to the drawing board, and a few months later, we had something working. The app visualized each athlete as a moving figure in a simulated kayak race. As they paddled on their machines, their avatars raced forward on the screen. It worked beautifully, and we were all proud of the result.

I wanted to test the app in the real world, so I suggested organizing an amateur race in my hometown. I knew some local kayak clubs and was confident people would show up, but my boss had a different idea.

Let’s do a real race. In a big European city. Let’s do it in Moscow.

We had a few weeks to prepare everything. I tested everything thoroughly—starting and stopping races a hundred times, trying different configurations, asking colleagues to help test in our company gym, and even spending long evenings paddling just to iron out any edge cases.

Things moved fast. In under two months, we were standing in a sports arena in Moscow, ready for the first-ever simulated kayak competition.

Problem #1: Asleep at the Start Line #

The first race went perfectly. The second one, too.

Then came the third race. There was a minor issue with the race list—someone mixed up the names—but it got sorted out. The athletes sat on their machines. Everyone was tense. The crowd was ready.

And then… one by one, the machines started turning off.

We had no idea what was going on. Panic. Confusion. What was happening?

We quickly powered them back on and restarted the race. Crisis averted—for now. But I needed to understand what had gone wrong.

The problem was simple: the devices had been idle for too long before the race started, and the battery-saving algorithm kicked in, shutting them down automatically. During development, we had assumed that five minutes of idle time was more than enough. But it wasn’t in a live event with last-minute changes and delays.

The fix was easy:

  • When the device receives the first RACE INIT command, it disables the power-saving mode until it’s manually turned off or runs out of battery.

Problem #2: Paddling Nowhere #

With that issue fixed, we kept moving forward.

But then another problem showed up.

The athletes were sitting on their machines. The race was about to start. I sent the start signal. They started paddling—and… nothing. Some of their avatars weren’t moving.

I stared at the screen, completely confused. There were no errors or warnings. The athletes were clearly paddling, but their figures just stood still. The race continued like that until the end of the day, and I never figured it out on the spot.

My temporary fix was to stop and restart the race, which usually worked. But it wasn’t a solution—it was a workaround.

Back in the office the following week, I finally found the root cause:

The application needed calibration data from each machine to calculate distance. And sometimes, the machine returned all zeros instead of valid calibration data.

If that happened, the race app could not calculate movement, so the avatar just stayed still.

The fix? Also simple:

  • If the app gets all-zero calibration data, send the request again.
  • If it happens twice, show a clear error message with instructions for resetting the device manually.

From that point on, the issue never surprised us again.

Problem #3: How a Folder Stopped a Race #

With those bugs behind us, we gained confidence. We knew that once the race started and all avatars moved, the system would run flawlessly until the end. The critical moment was the start—after that, we could finally breathe.

It was time for the final race of the event. Everyone was ready. The crowd was buzzing. Athletes sat on their machines, waiting. I gave the start signal.

The race began. Avatars moved. It worked.

I finally allowed myself to relax.

One of the local hosts, who had been helping with logistics the entire day, was sitting next to me. He was holding a folder in his hands, and just as we both leaned back in our chairs, he dropped the folder.

It flew through the air and landed directly on my laptop’s keyboard.

Right on the Escape key.

And what did I have programmed the Escape key to do?

  • Cancel the race.

Just like that, the screen went blank. Race canceled.

I turned to the guy and snapped:

You!? Idiot! Why would you do that?!

I’m still ashamed for flying off the handle and saying something hurtful to him.

But really, I was the idiot—not him.

Why would I assign such a critical action to a single keypress with no confirmation? It was a terrible design decision—a lazy shortcut.

The athletes took a 15-minute break. We restarted the race, and this time, everything went fine. As soon as it ended, I removed the Escape-to-cancel functionality from the software.

What I Learned #

This project taught me a lot, but one takeaway stands out:

No amount of testing can fully replicate production. Real users will always break things in ways you never expected.

Mocks, test suites, and staging environments are great and necessary—but they’ll never catch everything. The real bugs show up when your code meets reality. Shipping early is the fastest way to uncover what actually needs fixing.

Once I tackled those unexpected issues, the app ran flawlessly for years—and as far as I know, it’s still out there, quietly doing its job somewhere in the world.

Pro tip: don’t wire critical actions to a single keypress. And maybe keep folders out of keyboard range. Trust me.


If you’re curious to see what it all looked like—the tension before the start, the athletes paddling hard, and the virtual avatars racing neck and neck—a short video from the competition in Moscow captures the atmosphere.

Watch the video here and experience the race for yourself.